package com.sxt.provider.merchant.impl;

import com.sxt.commons.dto.ApiCreateOrderRequest;
import com.sxt.commons.typeEnum.ChannelTypeEnum;
import com.sxt.commons.typeEnum.OrderSettleStateEnum;
import com.sxt.commons.typeEnum.OrderStateEnum;
import com.sxt.commons.utils.ResultUtils;
import com.sxt.commons.utils.SignMD5Utils;
import com.sxt.pojo.entity.Cp;
import com.sxt.pojo.entity.CpChannel;
import com.sxt.pojo.entity.Order;
import com.sxt.provider.cp.CpChannelService;
import com.sxt.provider.cp.CpService;
import com.sxt.provider.merchant.CreateOrderProviderService;
import com.sxt.provider.order.OrderService;
import com.sxt.provider.sp.SpService;
import com.sxt.provider.sp.excutor.AbstractExcutor;
import com.sxt.provider.sp.excutor.ExcutorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

@Service("createOrderProvider")
public class CreateOrderProviderServiceImpl implements CreateOrderProviderService {
	Logger logger = LoggerFactory.getLogger(this.getClass());

	@Value("${api.response.sign.name}")
	String apiResponseSignName;
	@Value("${api.response.key.name}")
	String apiResponseKeyName;

	@Autowired
	OrderService orderService;
	@Autowired
	CpChannelService cpChannelService;
	@Autowired
	SpService spService;
	@Autowired
	CpService cpService;

	/**
	 * 创建订单
	 * @param request
	 * @return
	 */
	@Override
	public Map<String,Object> createOrder(ApiCreateOrderRequest request) throws Exception {

        //校验请求参数
        checkParams(request);
        //校验商户参数
		Cp cp = cpService.selectById(Long.valueOf(request.getMchId()));

        String payTypeName = ChannelTypeEnum.getInfo(request.getType());
        Assert.isTrue(!"".equals(payTypeName),"支付类型错误");
		CpChannel cpChannel = cpChannelService.getByCpIdAndChannelType(Long.valueOf(request.getMchId()),
				request.getType());
        Assert.notNull(cpChannel, "该商户没有开通"+payTypeName+"服务");
        Assert.isTrue(cpChannel.getState() == 0, "该商户的"+payTypeName+"已经被禁用");
        Assert.notNull(cpChannel.getFeeRecharge(), "该商户没有配置费率");
        Assert.notNull(cpChannel.getRateAdvince(), "该商户没有配置到账比率");
		//校验商户订单
        Order order = orderService.getByCpidAndOutTradeNo(Long.valueOf(request.getMchId()), request.getOutTradeNo());
        if (order != null) {
        	Assert.isTrue(Objects.equals(OrderStateEnum.NOTPAY.getType(), order.getState()),
					"无效的订单状态:" + OrderStateEnum.getByType(order.getState()).getInfo());
		}else {
        	//查询代理商Channel
			CpChannel agentChannel = cpChannelService.getAgentChannel(cpChannel);
			//组装订单信息
			order = generateOrder(request,cpChannel,agentChannel);
			//轮询通道
			order = orderService.selectASp(order, request.getType());
			//订单入库
			orderService.insert(order);
			if(order.getId() == null || order.getId() == 0) {
				logger.error("订单信息无法入库，order.id:" + order.getId());
				throw new Exception("无法生成订单");
			}
		}

        //调用接口执行器
        Map<String, Object> result = startExecuteFactory(order);

		//处理返回参数,并进行加签,暂时不加签，因为同步没必要
		//result = ResultUtils.signResult(result, cp.getSecretId(), apiResponseSignName, apiResponseKeyName);
		logger.info("请求返回："+result);
		return result;
	}

	@Override
	public String createSign(Map<String, Object> params, String mchId) throws Exception {
		Cp cp = cpService.selectById(Long.valueOf(mchId));
		Assert.notNull(cp, "商户不存在");
		String sign = SignMD5Utils.getSign(params,cp.getSecretId());
		return sign;
	}

	/**
	 * 执行工厂方法
	 * @param order
	 * @return
	 * @throws Exception
	 */
	public Map<String, Object> startExecuteFactory(Order order) throws Exception {
		Map<String, Object> result = null;
		try {
			ExcutorFactory excutorFactory = spService.getFactory(order.getSpId());
			result = selectFactory(excutorFactory,order.getChannelType()).excutor(order);
		}catch (Exception ex) {
			ex.printStackTrace();
			logger.error(order.getTradeNo() + ":" + order.getChannelType().toString()
					+ " -- 执行工厂方法出错:" + ex.toString());
		}
		return result;
	}

	/**
	 * 根据不同的支付类型，调用不用的工厂方法
	 * @param excutorFactory
	 * @param type
	 * @return
	 */
	private AbstractExcutor selectFactory(ExcutorFactory excutorFactory, Byte type){
		switch (type){
			case 1:
				return excutorFactory.createWxNativeExcutor();
			case 2:
				return excutorFactory.createAlipayNativeExcutor();
			case 3:
				return excutorFactory.createUnionNetExcutor();
			case 4:
				return excutorFactory.createWxMpPayExcutor();
			case 5:
				return excutorFactory.createQQNativeExcutor();
			case 6:
				return excutorFactory.createWxWapPayExcutor();
			case 7:
				return excutorFactory.createQQWapExcutor();
//			case 8:
//				return excutorFactory.createAlipays;
//			break;
			case 9:
				return excutorFactory.createAlipayWapExcutor();
			case 10:
				return excutorFactory.createJdNativeExcutor();
			case 11:
				return excutorFactory.createUnionNativeExcutor();
			case 12:
				return excutorFactory.createUnionQuickExcutor();

		}
		return null;
	}
	/**
	 * 校验
	 * @param request
	 */
	private void checkParams(ApiCreateOrderRequest request){
		Assert.notNull(request, "请输入交易信息");
		Assert.notNull(request.getBody(), "请输入商品描述");
		Assert.notNull(request.getMchId(), "请输入商户号");
		Assert.notNull(request.getOutTradeNo(), "请输入商户订单号");
		Assert.notNull(request.getTotalFee(), "请输入总金额");
		Assert.isTrue(request.getTotalFee() > 0, "金额太低");
		Assert.notNull(request.getMchCreateIp(), "请输入订单生成的机器 IP");
		Assert.notNull(request.getNotifyUrl(), "请输入notify_url");
		Assert.notNull(request.getNonceStr(), "请输入nonce_str");
		Assert.notNull(request.getType(), "请输入支付类型");
		Assert.notNull(request.getSign(), "请输入nonce_str");
	}

	/**
	 * 生成订单
	 * @param request
	 * @return
	 */
	private Order generateOrder(ApiCreateOrderRequest request,CpChannel cpChannel,CpChannel agentChannel){
		Order order = new Order();
		order.setCpId(Long.parseLong(request.getMchId()));
		order.setChannelType(request.getType());
		order.setBody(request.getBody());
		order.setAmount(request.getTotalFee());
		order.setFeeRecharge(cpChannel.getFeeRecharge());
		order.setState(OrderStateEnum.NOTPAY.getType());
		order.setTradeNo(orderService.generateTradeNo());
		order.setOutTradeNo(request.getOutTradeNo());
		order.setNotifyUrl(request.getNotifyUrl());
		order.setReturnUrl(request.getReturnUrl());
		order.setAttach(request.getAttach());
		order.setCreateTime(new Date());
		order.setSettleStatus(OrderSettleStateEnum.NOTSETTLE.getType());
		order.setRemark(request.getMchCreateIp());

		order.setFee(cpChannel.getFeeRecharge().multiply(
				new BigDecimal(request.getTotalFee().toString())).intValue());
		order.setActualAmount(order.getAmount() - order.getFee());
		order.setAdvanceAmount(cpChannel.getRateAdvince().multiply(
				new BigDecimal(order.getActualAmount().toString())).intValue());
		order.setDisableAmount(order.getActualAmount() - order.getAdvanceAmount());

		//是否有代理商
		if (agentChannel != null) {
			order.setAgentId(agentChannel.getCpId());
			order.setAgentFeeRecharge(agentChannel.getFeeRecharge());
			order.setAgentFee(agentChannel.getFeeRecharge().multiply(
					new BigDecimal(request.getTotalFee().toString())
			).intValue());
		}
		return order;
	}
}
